#include "lst_timer.h"
#include "../http/http_conn.h"

sort_timer_lst::sort_timer_lst()								//定时器容器类构造函数
{
    head = NULL;
    tail = NULL;
}
sort_timer_lst::~sort_timer_lst()								//析构函数
{
    util_timer *tmp = head;
    while (tmp)
    {
        head = tmp->next;
        delete tmp;
        tmp = head;
    }
}

void sort_timer_lst::add_timer(util_timer *timer)				//增加定时器
{
    if (!timer)
    {
        return;
    }
    if (!head)
    {
        head = tail = timer;
        return;
    }
    if (timer->expire < head->expire)
    {
        timer->next = head;
        head->prev = timer;
        head = timer;
        return;
    }
    add_timer(timer, head);										//否则，调用私有成员调整内部节点
}
void sort_timer_lst::adjust_timer(util_timer *timer)			//调整定时器，任务变化时调整定时器在链表中的位置
{
    if (!timer)
    {
        return;
    }
    util_timer *tmp = timer->next;
    if (!tmp || (timer->expire < tmp->expire))					//被调整的定时器在链表尾部      或者调整后的超值值仍小于其下一个定时器的超时值，不调整
    {
        return;
    }
    if (timer == head)											//被调整的定时器是链表的头结点，则将定时器取出，重新插入
    {
        head = head->next;
        head->prev = NULL;
        timer->next = NULL;
        add_timer(timer, head);
    }
    else														//在链表内部，一样取出重新插入
    {
        timer->prev->next = timer->next;
        timer->next->prev = timer->prev;
        add_timer(timer, timer->next);
    }
}
void sort_timer_lst::del_timer(util_timer *timer)				//删除定时器
{
    if (!timer)
    {
        return;
    }
    if ((timer == head) && (timer == tail))						//当前链表只有这一个节点，直接删除该定时器
    {
        delete timer;
        head = NULL;
        tail = NULL;
        return;
    }
    if (timer == head)											//被删除定时器为头结点
    {
        head = head->next;
        head->prev = NULL;
        delete timer;
        return;
    }
    if (timer == tail)											//为尾节点
    {
        tail = tail->prev;
        tail->next = NULL;
        delete timer;
        return;
    }
    timer->prev->next = timer->next;							//在链表内部，常规删除
    timer->next->prev = timer->prev;
    delete timer;
}
void sort_timer_lst::tick()										//定时任务处理函数
{
    if (!head)
    {
        return;
    }
    
    time_t cur = time(NULL);									//获取当前时间
    util_timer *tmp = head;
    while (tmp)													//便利定时器链表
    {
        if (cur < tmp->expire)									//因为链表为升序，因此若当前时间小于定时器的超时时间，后面也一定小于（未到期）
        {
            break;
        }
        tmp->cb_func(tmp->user_data);							//当前定时器到期，调用回调函数，执行定时事件
        head = tmp->next;										//删除处理过的定时器，并重置头结点
        if (head)
        {
            head->prev = NULL;
        }
        delete tmp;
        tmp = head;
    }
}

void sort_timer_lst::add_timer(util_timer *timer, util_timer *lst_head)			//私有成员，函数重载      主要被共有成员 add_timer 和 adjust_time 调用，用于调整链表的内部节点
{
    util_timer *prev = lst_head;
    util_timer *tmp = prev->next;
    while (tmp)															//遍历当前节点之后的链表，找到合适位置将其插入
    {
        if (timer->expire < tmp->expire)
        {
            prev->next = timer;
            timer->next = tmp;
            tmp->prev = timer;
            timer->prev = prev;
            break;
        }
        prev = tmp;
        tmp = tmp->next;
    }
    if (!tmp)															//遍历完成，则该节点需要放到尾节点
    {
        prev->next = timer;
        timer->prev = prev;
        timer->next = NULL;
        tail = timer;
    }
}

void Utils::init(int timeslot)
{
    m_TIMESLOT = timeslot;
}

//对文件描述符设置非阻塞
int Utils::setnonblocking(int fd)
{
    int old_option = fcntl(fd, F_GETFL);
    int new_option = old_option | O_NONBLOCK;
    fcntl(fd, F_SETFL, new_option);
    return old_option;
}

//将内核事件表注册读事件，ET模式，选择开启EPOLLONESHOT
void Utils::addfd(int epollfd, int fd, bool one_shot, int TRIGMode)
{
    epoll_event event;
    event.data.fd = fd;

    if (1 == TRIGMode)
        event.events = EPOLLIN | EPOLLET | EPOLLRDHUP;
    else
        event.events = EPOLLIN | EPOLLRDHUP;

    if (one_shot)
        event.events |= EPOLLONESHOT;
    epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &event);
    setnonblocking(fd);
}

//信号处理函数
void Utils::sig_handler(int sig)
{
    //为保证函数的可重入性，保留原来的errno						可重入性表示中断后再次进入该函数，环境变量与之前相同，不会丢失数据
    int save_errno = errno;
    int msg = sig;
    send(u_pipefd[1], (char *)&msg, 1, 0);						//将信号值从管道写端写入，传输字符类型，而非整型
    errno = save_errno;											//将原变量恢复
}

//设置信号处理函数
void Utils::addsig(int sig, void(handler)(int), bool restart)
{
    struct sigaction sa;										//创建sigaction结构体变量
    memset(&sa, '\0', sizeof(sa));
    sa.sa_handler = handler;									//信号处理回调函数由用户定义
    if (restart)
        sa.sa_flags |= SA_RESTART;
    sigfillset(&sa.sa_mask);									//将所有信号添加到信号集中
    assert(sigaction(sig, &sa, NULL) != -1);					//执行sigaction函数注册信号捕捉函数			修改要操作信号的处理动作
}

//定时处理任务，重新定时以不断触发SIGALRM信号
void Utils::timer_handler()
{
    m_timer_lst.tick();
    alarm(m_TIMESLOT);
}

void Utils::show_error(int connfd, const char *info)
{
    send(connfd, info, strlen(info), 0);
    close(connfd);
}

int *Utils::u_pipefd = 0;
int Utils::u_epollfd = 0;

class Utils;
void cb_func(client_data *user_data)							//定时事件（此处是 删除非活动socket上的注册时间，并关闭）		可由用户定义
{
    epoll_ctl(Utils::u_epollfd, EPOLL_CTL_DEL, user_data->sockfd, 0);			//删除非活动连接
    assert(user_data);
    close(user_data->sockfd);									//关闭文件描述符
    http_conn::m_user_count--;									//连接数减1
}
